﻿#include <mutex>
#include <map>
#include <tuple>
#include <sstream>

#include "stringutil.h"
#include "Reflectable.h"
#include "metatype.h"
#include "variant.h"

template <typename T>
T FromString(const std::string& input){
    std::stringstream stream;
    stream << input;
    T ret;
    stream >> ret;
    return ret;
}

typedef std::tuple<MetaTypeId,MetaTypeId> convertionId;

struct MetaType::Private{
    Private(){
        max_id = 0;
    }
    std::mutex mutex;
    std::map<int,MetaType::MetaTypeInfo> info;
    std::map<convertionId,convertFunction> convertions;
	std::map<std::string, MetaTypeId> alias;
    int max_id;

    friend class MetaType;
};


MetaType::MetaType()
{
    typeId = 0;
}

MetaType::MetaType(MetaTypeId typeId)
{
    this->typeId = typeId;
}

MetaType::MetaType(std::string name)
{
    this->typeId = FindInfo(name).id;
}

void *MetaType::Create(void *buffer,const void *other)
{
    MetaTypeInfo info = FindInfo(typeId);

    if(info.id == 0){
        return NULL;
    }

    if(buffer == NULL){
        buffer = new char[info.size];
    }

    if(other){
        info.copyCreate(buffer,other);
    }
    else{
        info.defaultCreate(buffer);
    }

    return buffer;
}

void MetaType::Destory(void *target)
{
    if(target == NULL){
        return;
    }

    MetaTypeInfo info = FindInfo(typeId);

    if(info.id == 0){
        return;
    }

    info.destory(target);
}

void MetaType::Delete(void *target)
{
    Destory(target);
    free(target);
}

void MetaType::Assign(void *target,const void *other)
{
    MetaTypeInfo info = FindInfo(typeId);

    if(info.id == 0){
        return;
    }

    info.assign(target,other);
}

bool MetaType::Equals(void *target, void *other)
{
    MetaTypeInfo info = FindInfo(typeId);

    if(info.id == 0){
        return false;
    }

    return info.equalOperate(target,other);
}

bool MetaType::IsConvertable(int output_type)
{
	auto info = FindInfo(typeId);
    if(!FindInfo(this->typeId).id){
        return false;
    }

	auto otherInfo = FindInfo(output_type);
    if(!otherInfo.id){
        return false;
    }

	if (output_type == typeId) {
		return true;
	}

	if (info.flag == TF_PointerToReflectable && otherInfo.flag == TF_PointerToReflectable) {
		return true;
	}

    auto _P = Instance_P();
    {
        convertionId id(typeId,output_type);
        std::lock_guard<std::mutex>(_P->mutex);
        if(_P->convertions.count(id)){
            return true;
        }
    }

    return false;
}

bool MetaType::Convert(void *input, int output_type, void *output)
{
    if(!input || !output){
        return false;
    }

    if(!IsConvertable(output_type)){
        return false;
    }

    auto _P = Instance_P();
    {
        convertionId id(typeId,output_type);
        std::lock_guard<std::mutex>(_P->mutex);
        if(_P->convertions.count(id)){
            auto f = _P->convertions[id];
            if(f){
                f(input,output);
                return true;
            }
        }
    }

	if (isPointerToReflectable() && MetaType(output_type).isPointerToReflectable()) {

		convertionId id(typeId, BT_ReflectablePointer);
		std::lock_guard<std::mutex>(_P->mutex);
		bool isOk = true;
		int * temp = NULL;
		void* tempPtr = &temp;
		if (_P->convertions.count(id)) {
			auto f = _P->convertions[id];
			if (f) {
				f(input, tempPtr);
				isOk = true;
			}
		}
		
		if (!isOk) {
			return false;
		}

		id = {BT_ReflectablePointer,typeId };
		if (_P->convertions.count(id)) {
			auto f = _P->convertions[id];
			if (f) {
				f(tempPtr, output);
				isOk = true;
			}
		}

		if (isOk) {
			return true;
		}
		
	}

    if(output_type == typeId){
        output = Create(output,input);
        return true;
    }

    return false;
}

bool MetaType::hasStreamOperator() const
{
    auto info = FindInfo(this->typeId);
    if(!info.id){
        return false;
    }

    return info.outputStream && info.inputStream;
}

void MetaType::Output(DataOutputStream &stream, const void *data)
{
    auto info = FindInfo(this->typeId);
    if(!info.id){
        return;
    }

    info.outputStream(&stream,data);
}

void MetaType::Input(DataInputStream &stream, void *data) throw (StreamException)
{
    auto info = FindInfo(this->typeId);
    if(!info.id){
        return;
    }

    info.inputStream(&stream,data);
}

int MetaType::Size()
{
    auto info = FindInfo(this->typeId);
    if(info.id){
        return info.size;
    }
    return 0;
}

bool MetaType::isValid()
{
    if(typeId == 0){
        return false;
    }

    if(FindInfo(typeId).id == 0){
        return false;
    }

    return true;
}

bool MetaType::isNativeType() const
{
    return typeId < Other;
}

bool MetaType::isCustomType() const
{
    return typeId >= Other;
}

MetaType::TypeFlag MetaType::GetTypeFlag() const {
	auto info = FindInfo(typeId);
	if (info.id == 0) {
		return MetaType::TypeFlag::TF_None;
	}

	return info.flag;
}

bool MetaType::isVector() const
{
	return GetTypeFlag() == TF_Vector;
}

MetaTypeId MetaType::GetVectorValueType() const
{
	auto info = FindInfo(typeId);
	if (info.id == 0) {
		return MetaType::TypeFlag::TF_None;
	}

	return info.vectorType;
}

bool MetaType::isMap() const
{
	return GetTypeFlag() == TF_Map;
}

MetaTypeId MetaType::GetMapKeyType() const
{
	auto info = FindInfo(typeId);
	if (info.id == 0) {
		return MetaType::TypeFlag::TF_None;
	}

	return info.mapKeyType;
}

MetaTypeId MetaType::GetMapValueType() const
{
	auto info = FindInfo(typeId);
	if (info.id == 0) {
		return MetaType::TypeFlag::TF_None;
	}

	return info.mapValueType;
}

bool MetaType::isPointerToReflectable() const
{
	return GetTypeFlag() == TF_PointerToReflectable;
}

MetaTypeId MetaType::Id() const
{
    return typeId;
}

std::string MetaType::Name() const
{
    auto info = FindInfo(typeId);
    if(info.id == 0){
        return "";
    }
    return info.name;
}

std::vector<std::string> MetaType::Alias() const
{
	return FindAlias(typeId);
}

void MetaType::UnRegisterType(std::string name)
{
    int id = 0;

    id = FindInfo(name).id;

    if(id > 0){
        UnRegisterType(id);
    }
}

void MetaType::UnRegisterType(MetaTypeId typeId)
{
    Private* P = Instance_P();
    std::lock_guard<std::mutex>(P->mutex);

    if(P->info.count(typeId)){
        P->info.erase(typeId);
    }
}

void MetaType::RegisterAlias(MetaTypeId type, const std::string name)
{
	Private* P = Instance_P();
	
	std::lock_guard<std::mutex>(P->mutex);
	if (P->info.count(type)) {
		P->alias[name] = type;
	}
}

void MetaType::RegisterConvertor(MetaTypeId in_type, MetaTypeId out_type, MetaType::convertFunction func)
{
    auto find = FindInfo(in_type);
    if(find.id == 0){
        return ;
    }

    find = FindInfo(out_type);
    if(find.id == 0){
        return ;
    }

    convertionId id(in_type,out_type);

    Private* P = Instance_P();

    {
        std::lock_guard<std::mutex>(P->mutex);
        P->convertions[id] = func;
    }
}

void MetaType::RegisterStreamOperator(MetaTypeId id,void (*output)(DataOutputStream *, const void *), void (*input)(DataInputStream *, void *) throw(StreamException))
{
    Private* P = Instance_P();
    std::lock_guard<std::mutex>(P->mutex);
    P->info[id].outputStream = output;
    P->info[id].inputStream = input;
}

MetaTypeId MetaType::_RegisterType(MetaType::MetaTypeInfo *metainfo)
{
    auto find = FindInfo(metainfo->name);
    if(find.id != 0){
        return find.id;
    }

    Private* P = Instance_P();
    std::lock_guard<std::mutex>(P->mutex);



    P->max_id ++;

    metainfo->id = P->max_id;
    P->info[P->max_id] = *metainfo;

    return metainfo->id;
}

MetaType::Private *MetaType::Instance_P()
{
    static Private _P;
    return &_P;
}

void MetaType::FinishNativeType()
{
    Private* P = Instance_P();
    std::lock_guard<std::mutex>(P->mutex);
    P->max_id = MetaType::Other;
}

MetaType::MetaTypeInfo MetaType::FindInfo(MetaTypeId typeId)
{
	std::lock_guard<std::mutex>(Instance_P()->mutex);
	return FindInfo_nolock(typeId);
}

std::vector<std::string> MetaType::FindAlias(MetaTypeId type_Id)
{
	Private* P = Instance_P();
	std::lock_guard<std::mutex>(P->mutex);

	std::vector<std::string> ret;

	for (auto i : P->alias) {
		if (i.second == type_Id)
		{
			ret.push_back(i.first);
		}
	}

	return ret;
}

MetaType::MetaTypeInfo MetaType::FindInfo(std::string name)
{
	std::lock_guard<std::mutex>(Instance_P()->mutex);
	return FindInfo_nolock(name);
}

MetaType::MetaTypeInfo MetaType::FindInfo_nolock(MetaTypeId typeId)
{
	MetaTypeInfo result;
	result.id = 0;
	if (typeId == 0) {
		return result;
	}

	Private* P = Instance_P();

	if (P->info.count(typeId)) {
		result = P->info.at(typeId);
		return result;
	}

	return result;
}

MetaType::MetaTypeInfo MetaType::FindInfo_nolock(std::string name)
{
	MetaTypeInfo result;
	result.id = 0;
	Private* P = Instance_P();

	{
		
		//查看是否存在别名
		if (P->alias.count(name)) {
			return FindInfo_nolock(P->alias[name]);
		}

		for (auto it : P->info) {
			if (it.second.name == name) {
				result = it.second;
				break;
			}
		}
	}

	return result;
}

bool isInteger(int in_type){
    if(in_type >= MetaType::BT_Char&& in_type <= MetaType::BT_ULongLong){
        return true;
    }
    return false;
}

bool isNumber(int in_type){
    if(in_type >= MetaType::BT_Char&& in_type <= MetaType::BT_Double){
        return true;
    }
    return false;
}

bool isStringType(int in_type){
    if(in_type == MetaType::BT_StdString || in_type == MetaType::BT_StdWString)
    {
        return true;
    }
    return false;
}



struct MetaType::Initialize{
    Initialize(){
        //Initialize Types
		REGISTER_META_TYPE(bool)
		REGISTER_META_TYPE(char);
		REGISTER_META_TYPE(signed char);
		REGISTER_META_TYPE(unsigned char);
		REGISTER_META_TYPE(int);
		REGISTER_META_TYPE(unsigned int);
		REGISTER_META_TYPE(short);
		REGISTER_META_TYPE(unsigned short);
		REGISTER_META_TYPE(long);
		REGISTER_META_TYPE(unsigned long);
		REGISTER_META_TYPE(long long);
		REGISTER_META_TYPE(unsigned long long);
        REGISTER_META_TYPE(float);
        REGISTER_META_TYPE(double);
        REGISTER_META_TYPE(std::string);
        REGISTER_META_TYPE(std::wstring);
        REGISTER_META_TYPE(ByteArray);
		REGISTER_META_TYPE(Size2F);
		REGISTER_META_TYPE(Size2I);
		REGISTER_META_TYPE(Size3F);
		REGISTER_META_TYPE(Size3I);
		REGISTER_META_TYPE(Point2F);
		REGISTER_META_TYPE(Point2I);
		REGISTER_META_TYPE(Point3F);
		REGISTER_META_TYPE(Point3I);
		REGISTER_META_TYPE(Rect2F);
		REGISTER_META_TYPE(Rect2I);
		REGISTER_META_TYPE(Rect3F);
		REGISTER_META_TYPE(Rect3I);
		REGISTER_META_TYPE(ColorF);
		REGISTER_META_TYPE(ColorI);
		REGISTER_META_TYPE(Image);
		REGISTER_META_TYPE(Variant);
        REGISTER_META_TYPE(VariantList);
        REGISTER_META_TYPE(VariantWMap);
        REGISTER_META_TYPE(VariantMap);
		REGISTER_META_TYPE(Reflectable*);
        MetaType::FinishNativeType();

		REGISTER_ALIAS(int8_t);
		REGISTER_ALIAS(uint8_t);
		REGISTER_ALIAS(int16_t);
		REGISTER_ALIAS(uint16_t);
		REGISTER_ALIAS(int32_t);
		REGISTER_ALIAS(uint32_t);
		REGISTER_ALIAS(int64_t);
		REGISTER_ALIAS(uint64_t);

		MetaType::RegisterStreamOperator<bool>();
		MetaType::RegisterStreamOperator<char>();
		MetaType::RegisterStreamOperator<signed char>();
		MetaType::RegisterStreamOperator<unsigned char>();
		MetaType::RegisterStreamOperator<int>();
		MetaType::RegisterStreamOperator<unsigned int>();
		MetaType::RegisterStreamOperator<short>();
		MetaType::RegisterStreamOperator<unsigned short>();
		MetaType::RegisterStreamOperator<long>();
		MetaType::RegisterStreamOperator<unsigned long>();
		MetaType::RegisterStreamOperator<long long>();
		MetaType::RegisterStreamOperator<unsigned long long>();
        MetaType::RegisterStreamOperator<float>();
        MetaType::RegisterStreamOperator<double>();
        MetaType::RegisterStreamOperator<std::string>();
        MetaType::RegisterStreamOperator<std::wstring>();
        MetaType::RegisterStreamOperator<ByteArray>();
		MetaType::RegisterStreamOperator<Size2F>();
		MetaType::RegisterStreamOperator<Size2I>();
		MetaType::RegisterStreamOperator<Size3F>();
		MetaType::RegisterStreamOperator<Size3I>();
		MetaType::RegisterStreamOperator<Point2F>();
		MetaType::RegisterStreamOperator<Point2I>();
		MetaType::RegisterStreamOperator<Point3F>();
		MetaType::RegisterStreamOperator<Point3I>();
		MetaType::RegisterStreamOperator<Rect2F>();
		MetaType::RegisterStreamOperator<Rect2I>();
		MetaType::RegisterStreamOperator<Rect3F>();
		MetaType::RegisterStreamOperator<Rect3I>();
		MetaType::RegisterStreamOperator<ColorF>();
		MetaType::RegisterStreamOperator<ColorI>();
		MetaType::RegisterStreamOperator<Image>();
		MetaType::RegisterStreamOperator<Variant>();
        MetaType::RegisterStreamOperator<VariantList>();
        MetaType::RegisterStreamOperator<VariantWMap>();
        MetaType::RegisterStreamOperator<VariantMap>();
		

    }
}i;
